import numpy as np


def simulated_annealing(
        init_solution,
        turbed_solution_generator,
        cost_calculator,
        init_temp=1000,
        stop_temp=1,
        cooling_factor=0.99,
        iteration_count=10):
    current_temp = init_temp
    current_solution = init_solution
    current_cost = cost_calculator(current_solution)

    while current_temp > stop_temp:
        for i in range(0, iteration_count):
            new_solution = turbed_solution_generator(current_solution)
            new_cost = cost_calculator(new_solution)

            cost_diff = new_cost - current_cost

            if (cost_diff < 0
                    or np.random.random() < np.exp(-cost_diff / current_temp)):
                current_solution = new_solution
                current_cost = new_cost

        current_temp *= cooling_factor

    return current_solution, current_cost
